package com.adwyxx.type;

import java.io.Serializable;
import java.lang.annotation.*;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;

/**
 * 类型变量 {@link TypeVariable}
 * 类型变量: 用于描述类型，表示泛指任意或相关一类类型，也可以说狭义上的泛型（泛指某一类类型），一般用大写字母作为变量，比如 T、K、V、E 等。
 * 所以使用 instanceof TypeVariable 方法的目的：是判断一个类型是否是泛型变量（T,K,V,U,E等）,而不是一个具体类型
 * TypeVariable 接口的方法：
 * 1. Type[] getBounds() -> 获得泛型变量声明的上限，若未明确声明上边界( ? extends XXX ),则默认为Object
 * 2. D getGenericDeclaration() -> 获取声明该类型变量实体(即:获得类、方法或构造器名)
 * 3. String getName() -> 获得泛型变量的名称，即:K、V、E之类名称
 * 4. AnnotatedType[] getAnnotatedBounds() -> 获得泛型变量带有注解的泛型上限
 *
 * 使用 Class.getTypeParameters() 方法，可以获取一个泛型类声明的所有类型变量，返回 TypeVariable 数组
 * 使用 Method.getTypeParameters() 方法，可以获取一个泛型方法声明的所有类型变量，返回 TypeVariable 数组
 *
 * @author Leo
 * @date 2024/8/20 9:20
 */
public class TypeVariableDemo<K, V extends Number & Serializable> {
    private K key;
    private V value;
    private Map<K, V> map;

    // 自定义注解，用于泛型类声明时注解在类型参数上
    // TYPE_USE（Java 8新增）：类型使用声明。这是一个非常灵活的注解目标，它可以应用于几乎任何使用类型的地方，包括泛型类型参数、非泛型类型参数、返回类型、抛出类型以及实现类型等。
    @Target(ElementType.TYPE_USE) // 元注解 @Target 指定注解可以应用的程序元素类型
    @Retention(RetentionPolicy.RUNTIME) // 元注解 @Retention 指定注解的保留策略，RUNTIME 运行时有效
    public @interface Location {
        String value() default "default"; // 注解的属性
    }

    // 使用注解 @Location
    public static <T extends Number &  @Location("Serializable") Serializable  & @Location("Comparable<T>") Comparable<T>> void test(T t) {

    }

    public static void main(String[] args) throws NoSuchMethodException {
        TypeVariable[] types = TypeVariableDemo.class.getTypeParameters();
        for (TypeVariable type : types) {
            // getName() -> 获得“范型变量”在声明（定义）时候的名称: K,V。
            System.out.println(type.getName());
            // getGenericDeclaration() -> 获得“范型变量”在声明（定义）时的类名、方法名或构造器名。
            System.out.println("声明 TypeVariable 的类 -> " + type.getGenericDeclaration());
            // getBounds() -> 获得“范型变量”在声明（定义）时设定的上限，若未明确声明上边界( T extends XXX ),则默认为 Object
            // 类型变量的上限可能不止一个，因为可以用&符号限定多个（这其中有且只能有一个为类或抽象类，且必须放在extends后的第一个，即若有多个上边界，则第一个&后必为接口）
            Type[] boundTypes = type.getBounds();
            for (Type boundType : boundTypes) {
                System.out.println(boundType);
            }
            System.out.println();
        }

        Method method = TypeVariableDemo.class.getMethod("test", Number.class);
        TypeVariable[] mtypes = method.getTypeParameters();
        for (TypeVariable mtype : mtypes) {
            System.out.println("TypeVariable name -> " + mtype.getName());
            System.out.println("声明 TypeVariable 的方法 -> " + mtype.getGenericDeclaration());
            // System.out.println(mtype.getBounds()[0]);
            // getAnnotatedBounds() -> 获得“范型变量”在声明（定义）时设定的带有注解的上限，若未明确声明上边界( ? extends XXX ),则默认为 Object
            // AnnotatedType 接口用来代表被注解修饰的类型，可以获取变量上线类型的 AnnotatedType 封装类型数组，通过getType()，可以获取类型名称
            AnnotatedType[] annotatedTypes = mtype.getAnnotatedBounds();
            for (AnnotatedType annotatedType : annotatedTypes) {
                System.out.println("AnnotatedType -> " + annotatedType.getType());
                Annotation[] annotations = annotatedType.getDeclaredAnnotations();
                for (int k = 0; k < annotations.length; k++) {
                    Annotation annotation = annotations[k];
                    System.out.println("AnnotatedType -> Annotation -> " + annotation.toString());
                }
            }
            System.out.println();
        }
    }
}

